home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
demos
/
video
/
trails.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
19KB
|
703 lines
/*
* Copyright (C) 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
* File: trails.c
*
* Usage: trails.c [-f] [-d] [-n devicenum] [-t title]
* [-v videosource] [-I] [-h]
*
*
* Description: Modification of simpleblend to use frame buffer connected to
* blender output, and then fed back into blender background.
* Simpleblend is an example of blending video with graphics. It
* does not do any special setup, but it does show the output
* in a graphics window and on video out. This program only
* runs on video hardware that has a video output port.
* This program will only run on the Galileo or IndyVideo board
*
* Functions: SGI Video Library functions used (see other modules)
*
* vlOpenVideo()
* vlGetDeviceList()
* vlGetNode()
* vlCreatePath()
* vlAddNode()
* vlGetDevice()
* vlSetupPaths()
* vlSelectEvents()
* vlRegisterHandler()
* vlAddCallback()
* vlSetControl()
* vlGetControl()
* vlMainLoop()
* vlBeginTransfer()
* vlEndTransfer()
* vlDestroyPath()
* vlCloseVideo()
* vlGetErrno()
* vlPerror()
* vlStrError()
*
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <Xm/MwmUtil.h>
#include <vl/vl.h>
#include <vl/dev_ev1.h>
#include <gl/gl.h>
#include <gl/device.h>
/*
* Function prototypes
*/
void VideoTracking(Window, int,int);
void processXEvent(uint, void *);
void processVLEvent(VLServer, VLEvent *, void *);
void docleanup(void);
void usage(void);
VLServer vlSvr = NULL;
VLPath vlPath = -1;
VLDevList devlist;
VLNode src_vid;
VLNode src_scr;
VLNode drn_scr;
VLNode drn_vid;
VLNode drn_mem; /* memory drain (frame buffer) */
VLNode mydev_node; /* device node to allow setting of sync mode */
VLNode blend_node; /* 'cause blending controls are here */
VLBuffer buffer;
int imageCount = 1;
Display *dpy;
Window drnwin;
int vin = VL_ANY;
char *_progname;
char *deviceName;
int devicenum = -1;
int ev1num = -1;
int debug = 0;
Atom WM_DELETE_WINDOW;
Atom WM_PROTOCOLS;
int lastw = 0, lasth = 0;
#define Debug if (debug) printf
#define fDebug if (debug) fprintf
#define ESC_KEY '\006'
#define USAGE \
"%s: [-f] [-n <devicenum>] [-t] [-d] [-I] [-v <videonode> ] [-h]\n\
\t-f\tdisable forking\n\
\t-n n\tdevice number to use\n\
\t-t\tset window title\n\
\t-d\tdebug mode\n\
\t-I\tprint node and path IDs for command line interface users\n\
\t-v n\tvideo source node number n\n\
\t-h\tthis help message\n"
void
usage()
{
fprintf(stderr, USAGE, _progname);
}
/* Constrain the window's aspect ratio */
void
constrainWindowResize(Display *dpy, Window win, int max_w, int max_h)
{
XSizeHints xsh;
xsh.min_aspect.x = xsh.max_aspect.x = 80;
xsh.min_aspect.y = xsh.max_aspect.y = 60;
xsh.min_width = max_w;
xsh.min_height = max_h;
xsh.max_width = max_w;
xsh.max_height = max_h;
xsh.flags = PAspect|PMinSize|PMaxSize;
XSetWMNormalHints(dpy, win, &xsh);
XResizeWindow(dpy, win, max_w, max_h);
}
simplev2v()
{
VLServer svr;
VLPath VIDPath;
VLNode src, drn;
int c;
int devicenum = -1;
char *_progName;
/* Connect to the daemon */
if (!(svr = vlOpenVideo("")))
{
printf("%s: can't open video: %s\n", _progName, vlStrError(vlGetErrno()));
docleanup();
}
/* Set up a source node on the first available video device */
src = vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY);
/* Set up a video drain node on the first device that has one */
drn = vlGetNode(svr, VL_DRN, VL_VIDEO, VL_ANY);
/* Create a path using the selected device(s) */
if (devicenum == -1)
VIDPath = vlCreatePath(svr, VL_ANY, src, drn);
else
VIDPath = vlCreatePath(svr, devicenum, src, drn);
/* Set up the hardware for and define the usage of the path */
if (vlSetupPaths(svr, (VLPathList)&VIDPath, 1, VL_SHARE, VL_SHARE)<0)
{
printf("%s: can't setup path: %s\n", _progName, vlStrError(vlGetErrno()));
docleanup();
}
/* Begin the data transfer */
vlBeginTransfer(svr, VIDPath, 0, NULL);
/* End the data transfer */
vlEndTransfer(svr, VIDPath);
/* Clean up and exit */
vlDestroyPath(svr, VIDPath);
vlCloseVideo(svr);
}
main(int argc, char **argv)
{
char *winname = NULL;
int opterr = 0;
int c,i;
int dev;
int ret;
int nofork = 0;
int x, y;
int print_ids = 0;
Atom WM_PROT_SET[2];
Atom _SGI_VIDEO;
VLControlValue val;
int myret;
VLTransferDescriptor xferDesc;
_progname = argv[0];
/*
* Parse command line options
* -f disable forking
* -n n device number n
* -d set debugging
* -t set title
* -v n use video input n
* -I print node and path IDs
* -h display help message
*/
while ((c = getopt(argc, argv, "t:dv:In:fh")) != EOF)
{
switch(c)
{
case 'f':
nofork = 1;
break;
case 'n':
devicenum = atoi(optarg);
break;
case 'd':
debug++;
break;
case 't':
winname = optarg;
break;
case 'I':
print_ids = 1;
break;
case 'v':
vin = atoi(optarg);
Debug("video input = %d\n", vin);
break;
case 'h':
usage();
exit(0);
break;
}
}
if (opterr)
{
usage();
exit(1);
}
/* Run in background if no-forking option not set */
if (!nofork)
{
ret = fork();
switch (ret)
{
case 0:
break;
case -1:
fprintf(stderr, "%s: can't fork\n");
exit(1);
break;
default:
exit(0);
break;
}
}
/* Connect to the daemon */
if (!(vlSvr = vlOpenVideo("")))
{
printf("%s: opening video: %s\n",_progname,vlStrError(vlGetErrno()));
exit(1);
}
/* Get the list of devices the daemon supports */
if (vlGetDeviceList(vlSvr, &devlist) < 0)
{
printf("%s: getting device list: %s\n",_progname,vlStrError(vlGetErrno()));
exit(1);
}
/* Make sure that the device the user requested (if any) is in the list */
if ((devicenum >= (int)devlist.numDevices) || (devicenum < -1))
{
if (devlist.numDevices == 1)
fprintf(stderr,"%s: The device number must be 0\n",_progname);
else
fprintf(stderr,"%s: The device number must be between 0 and %d\n",
_progname, devlist.numDevices-1);
exit(1);
}
/* find ev1 */
for (i=0; i<devlist.numDevices; i++)
if (strcmp(devlist.devices[i].name,"ev1") == 0)
ev1num = i;
if ( (ev1num == -1) /* no ev1 found ... OR ...*/
|| ((devicenum != -1) && (devicenum != ev1num))) /* non ev1 specified*/
{
printf("This program requires 'ev1' hardware.\a\n");
if (ev1num != -1)
printf("Use device number '%d', or use the default mode\n",ev1num);
exit(1);
}else
{
printf("Setting device number to %d\n", ev1num);
devicenum = ev1num; /* allow default to work */
}
/*
* Establish a path between the screen source and video
* drain. Then add a video source node and a screen drain
* node.
*/
/* Setup drain nodes on the screen and video */
drn_scr = vlGetNode(vlSvr, VL_DRN, VL_SCREEN, VL_ANY);
Debug("drn_scr = %d\n", drn_scr);
drn_vid = vlGetNode(vlSvr, VL_DRN, VL_VIDEO, VL_ANY);
Debug("drn_vid = %d\n", drn_vid);
/* Setup source nodes on the screen and video */
src_scr = vlGetNode(vlSvr, VL_SRC, VL_SCREEN, VL_ANY);
Debug("src_scr = %d\n", src_scr);
src_vid = vlGetNode(vlSvr, VL_SRC, VL_VIDEO, vin);
Debug("src_vid = %d\n", src_vid);
/* Set up a drain node in memory (frame buffer) */
drn_mem = vlGetNode(vlSvr, VL_DRN, VL_MEM, VL_ANY);
Debug("drn_mem = %d\n", drn_mem);
mydev_node = vlGetNode(vlSvr, VL_DEVICE, 0,0);
Debug("mydev_node = %d\n", mydev_node);
blend_node = vlGetNode(vlSvr, VL_INTERNAL, VL_BLENDER, VL_ANY);
Debug("blend_node = %d\n", blend_node);
vlPath = -1;
/* If no device was specified... */
if (devicenum == -1)
{
/* Try to create the screen to video path */
vlPath = vlCreatePath(vlSvr, devicenum, src_scr, drn_vid);
Debug("vlPath = %d\n", vlPath);
/* Add the video source and screen drain nodes */
ret = vlAddNode(vlSvr, vlPath, src_vid);
Debug("vlAddNode(src_vid) returns %d\n", ret);
if (!ret)
ret = vlAddNode(vlSvr, vlPath, drn_scr);
Debug("vlAddNode(drn_scr) returns %d\n", ret);
if (ret)
{ /* Device doesn't support this path, these nodes */
vlDestroyPath(vlSvr, vlPath);
vlPath = -1;
}
else
{ /* Path OK, get device info */
devicenum = vlGetDevice(vlSvr, vlPath);
Debug("devicenum = %d\n", devicenum);
deviceName = devlist.devices[devicenum].name;
Debug("deviceName = %s\n", deviceName);
}
}
else /* User specified a device */
{ /* Get the device info */
deviceName = devlist.devices[devicenum].name;
/* Try to create the screen to video path */
vlPath = vlCreatePath(vlSvr, devicenum, src_scr, drn_vid);
/* Add the video source and screen drain nodes */
ret = vlAddNode(vlSvr, vlPath, src_vid);
if (!ret)
ret = vlAddNode(vlSvr, vlPath, drn_scr);
if (ret)
{ /* Device doesn't support this path, these nodes */
vlDestroyPath(vlSvr, vlPath);
vlPath = -1;
}
}
if (vlAddNode(vlSvr, vlPath, drn_mem))
{
vlPerror("Add memory drain Node");
vlDestroyPath(vlSvr, vlPath);
vlPath = -1;
}
Debug("vlAddNode(drn_mem)\n");
if (vlAddNode(vlSvr, vlPath, mydev_node))
{
vlPerror("Add Device Node");
vlDestroyPath(vlSvr, vlPath);
vlPath = -1;
}
Debug("vlAddNode(mydev_node)\n");
if (vlAddNode(vlSvr, vlPath, blend_node))
{
vlPerror("Add blend Node");
vlDestroyPath(vlSvr, vlPath);
vlPath = -1;
}
Debug("vlAddNode(blend_node)\n");
if (vlPath == -1)
{ /* Couldn't create the path, quit */
vlPerror("Path Setup");
docleanup();
}
/* Print the node and path IDs for cmd line users */
if (print_ids)
{
printf("SIMPLEBLEND NODE IDs:\n");
printf("screen source = %d\n", src_scr);
printf("video source = %d\n", src_vid);
printf("screen drain = %d\n", drn_scr);
printf("video drain = %d\n", drn_vid);
printf("blend = %d\n", blend_node);
printf("PATH ID = %d\n", vlPath);
}
/* Set up the hardware for and define the usage of the path */
if (vlSetupPaths(vlSvr, (VLPathList)&vlPath, 1, VL_SHARE, VL_SHARE) < 0)
{
vlPerror("Error in device paths setup");
printf("This program requires the device Sync to be in slave mode.\n");
printf("Use the videopanel to set the device Sync to be slave.\n");
exit(1);
}
Debug("vlSetupPaths()\n");
printf("\nFor best results, use the blending controls provided\n");
printf("by the program /usr/people/4Dgifts/examples/video/vl/keyctls.\n");
printf("Interesting results can also be obtained by changing values\n");
printf("in the Pro/Video Input and Pro/Video Output control panels of \n");
printf("the videopanel.\n\n");
printf("Type 'q' inside the video window to quit\n\n");
/* Get the current size of the drain window */
vlGetControl(vlSvr, vlPath, drn_scr, VL_SIZE, &val);
lastw = val.xyVal.x;
lasth = val.xyVal.y;
/* Attempt to set the source to the same size */
vlSetControl(vlSvr, vlPath, src_scr, VL_SIZE, &val);
/* Make sure there's enough room for a source window of the same size */
vlGetControl(vlSvr, vlPath, src_scr, VL_SIZE, &val);
if (lastw != val.xyVal.x || lasth != val.xyVal.y)
{
printf("%s: unable to make two full size windows\n", _progname);
docleanup();
}
/* Set the keyer mode, keyer source and blend controls */
val.intVal = VL_EV1_KEYERMODE_LUMA;
vlSetControl(vlSvr, vlPath, blend_node, VL_EV1_KEYER_MODE, &val);
val.intVal = src_scr;
vlSetControl(vlSvr, vlPath, blend_node, VL_EV1_KEYER_SOURCE, &val);
/* val.intVal = src_scr; */
val.intVal = src_vid;
vlSetControl(vlSvr, vlPath, blend_node, VL_BLEND_A, &val);
/* val.intVal = src_vid; */
val.intVal = drn_mem;
vlSetControl(vlSvr, vlPath, blend_node, VL_BLEND_B, &val);
val.intVal = 7;
vlSetControl(vlSvr,vlPath, blend_node, VL_EV1_KEYER_DETAIL, &val);
val.intVal = 255;
vlSetControl(vlSvr,vlPath, blend_node, VL_EV1_KEYER_FG_OPACITY, &val);
val.intVal = 10;
vlSetControl(vlSvr,vlPath, blend_node, VL_EV1_KEYER_VALUE_LUMA, &val);
val.intVal = 10;
vlSetControl(vlSvr,vlPath, blend_node, VL_EV1_KEYER_RANGE_LUMA, &val);
/* Display the drain window */
if (!(dpy = XOpenDisplay("")))
{
printf("%s: can't open display\n", _progname);
docleanup();
}
drnwin = XCreateWindow(dpy, RootWindow(dpy, 0), 0, lasth, lastw, lasth, 0,
CopyFromParent, CopyFromParent, CopyFromParent,
(ulong) 0, NULL);
_SGI_VIDEO = XInternAtom(dpy, "_SGI_VIDEO", False);
WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
WM_PROT_SET[0] = WM_DELETE_WINDOW;
WM_PROT_SET[1] = _SGI_VIDEO;
XSetWMProtocols(dpy,drnwin, WM_PROT_SET, 2);
XStoreName(dpy, drnwin, "Video Trails");
/* Adjust the drain window's aspect ratio */
constrainWindowResize(dpy, drnwin, lastw, lasth);
/* Set the video to appear in window drnwin */
val.intVal = drnwin;
vlSetControl(vlSvr, vlPath, drn_scr, VL_WINDOW, &val);
/* Make sure there's room for both the source and drain window */
vlGetControl(vlSvr, vlPath, drn_scr, VL_SIZE, &val);
if (val.xyVal.x != lastw || val.xyVal.y != lasth)
{
printf("%s: Unable to setup two full size windows\n",_progname);
docleanup();
}
vlGetControl(vlSvr, vlPath, src_scr, VL_SIZE, &val);
if (val.xyVal.x != lastw || val.xyVal.y != lasth)
{
printf("%s: Unable to setup two full size windows\n",_progname);
docleanup();
}
/* Get the location of the screen drain */
vlGetControl(vlSvr, vlPath, drn_scr, VL_ORIGIN, &val);
/* Move its window to that location */
XMoveWindow(dpy, drnwin, val.xyVal.x, val.xyVal.y);
XMapWindow(dpy, drnwin);
XSelectInput(dpy, drnwin, KeyPressMask|VisibilityChangeMask
|ExposureMask|StructureNotifyMask);
XSync(dpy, 0);
/* Specify a file descriptor and pending check function for VL events */
vlRegisterHandler(vlSvr, ConnectionNumber(dpy), processXEvent,
(VLPendingFunc)XPending, dpy);
/* Set up event handler routine as callback for all events */
vlAddCallback(vlSvr, vlPath, VLAllEventsMask, processVLEvent, NULL);
/* Set the VL event mask so we only get control changed events */
vlSelectEvents(vlSvr, vlPath, VLControlChangedMask);
/* ### */
/* Create and register a buffer of imageCount frames... */
buffer = vlCreateBuffer(vlSvr, vlPath, drn_mem, imageCount);
if (buffer == NULL)
{
vlPerror("trails");
docleanup();
}
if (vlRegisterBuffer(vlSvr, vlPath, drn_mem, buffer))
{
vlPerror("trails");
docleanup();
}
/*
* Fill the transfer descriptor for a discrete transfer of imageCount
* frames. If the external trigger option is set, we use VLDeviceEvent
* for a trigger, otherwise trigger immediately. Note that this may not
* work well on all devices, as VLDeviceEvent it not well-defined.
*/
xferDesc.mode = VL_TRANSFER_MODE_DISCRETE;
xferDesc.count = imageCount;
xferDesc.delay = 0;
xferDesc.trigger = VLTriggerImmediate;
/* Start the data transfer immediately (i.e. don't wait for trigger) */
myret = vlBeginTransfer(vlSvr, vlPath, 1, &xferDesc);
Debug("vlBeginTransfer() = %d\n", myret);
/* Handle event dispatching */
vlMainLoop();
}
/*
* VideoTracking - if the user changes the size of the window,
* update the video to reflect the new size and position.
*/
void
VideoTracking(Window win, int x, int y)
{
Window dummyWin;
VLControlValue val;
/* Get X's idea of origin */
XTranslateCoordinates(dpy, win, RootWindow(dpy, DefaultScreen(dpy)),
0, 0,
&x, &y,
&dummyWin);
/* Try to make vl match X */
val.xyVal.x = x;
val.xyVal.y = y;
if (win == drnwin)
vlSetControl(vlSvr, vlPath, drn_scr, VL_ORIGIN, &val);
else
vlSetControl(vlSvr, vlPath, src_scr, VL_ORIGIN, &val);
}
/*
* VLEvent processing for video to screen.
* We only deal with control changed events.
*/
void
processVLEvent(VLServer vlSvr, VLEvent *ev, void *dummy)
{
VLControlChangedEvent *cev = (VLControlChangedEvent *) ev;
VLControlValue val;
Debug("VL event.type = %d\n", ev->reason);
switch (ev->reason)
{ /* Ignore all but a change in the drain's location */
case VLControlChanged:
if ((cev->type == VL_ORIGIN)&&(cev->node == drn_scr))
{
/* Drain moved, move window accordingly */
vlGetControl(vlSvr, vlPath, drn_scr, VL_ORIGIN, &val);
XMoveWindow(dpy, drnwin, val.xyVal.x, val.xyVal.y);
}
break;
}
}
/* XEvent processing for video to screen */
void
processXEvent(uint fd, void *source)
{
int i;
if (source == (caddr_t)dpy)
{
XEvent ev;
XNextEvent(dpy, &ev);
switch (ev.type)
{
case ClientMessage:
if (ev.xclient.message_type == WM_PROTOCOLS)
if (ev.xclient.data.l[0] == WM_DELETE_WINDOW)
docleanup();
break;
case Expose: /* These really don't effect us */
case GraphicsExpose:
case VisibilityNotify:
break;
case ConfigureNotify: /* Window moved or changed size */
VideoTracking(ev.xany.window, ev.xconfigure.x,ev.xconfigure.y);
break;
case KeyPress:
{
XKeyEvent *kev = (XKeyEvent *)&ev;
KeySym keysym;
char buf[4];
XLookupString(kev, buf, 1, &keysym, 0);
switch (buf[0])
{
case '+':
/* Quit */
case 'q':
case 'Q':
case ESC_KEY:
docleanup();
break;
default:
break;
}
}
}
}
}
/* Dispose of the vl structures */
void
docleanup(void)
{ /* End the data transfer */
vlEndTransfer(vlSvr, vlPath);
/* Destroy the path, free it's memory */
vlDestroyPath(vlSvr, vlPath);
/* Disonnect from the daemon */
vlCloseVideo(vlSvr);
simplev2v(); /* make sure leave in 'nice' state */
exit(0);
}